package secondriver.ccs.parallel;

import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

/**
 * Author : secondriver
 */
public final class CcsComputeTaskUnit extends RecursiveTask<String> implements CcsCommon {


    private final int edge;
    private final int sid;
    private final byte[] operator;

    /**
     * 中间状态记录
     */
    private final byte[] status;

    /**
     * 构造任务单元
     *
     * @param edge [1,32)
     * @param sid  [0,pow(2,edge))
     */
    public CcsComputeTaskUnit(int edge, int sid) {
        int max = (int) Math.pow(MOD_TWO, edge);
        if (sid < 0 || sid >= max) {
            throw new IllegalArgumentException("parameter sid must be 0<= sid < " + max + " .");
        }
        this.edge = edge;
        this.sid = sid;
        int size = edge * edge;
        this.status = new byte[size];
        this.operator = new byte[size];

        int column = 0;
        int tempSid = sid;
        while (true) {
            if (tempSid == 0) {
                break;
            }
            byte tag = (byte) (tempSid % MOD_TWO);
            if (tag == ONE) {
                operator[column] = ONE;
            }
            tempSid /= MOD_TWO;
            column++;
        }
    }

    @Override
    protected String compute() {
        System.out.println("CcsComputeTaskUnit-Compute: edge=" + edge + ", sid=" + sid + "...");

        // 遍历第0行
        for (int column = 0; column < edge; column++) {
            if (operator[column] == ONE) {
                changeStatus(column);
            }
        }
        // 遍历第[1, edge)行
        for (int row = 1; row < edge; row++) {
            for (int column = 0; column < edge; column++) {
                int index = row * edge + column;
                int top = index - edge;
                if (status[top] == ZERO) {
                    operator[index] = ONE;
                    changeStatus(index);
                }
            }
        }
        // 计算结束
        boolean result = true;
        for (int i = 0, len = status.length; i < len; i++) {
            if (status[i] == ZERO) {
                result = false;
                break;
            }
        }
        String fileName = NO_FILE;
        if (result) {
            ComputeResult computeResult = new ComputeResult(edge, sid, operator);
            CreatorFileTaskUnit creatorFileTaskUnit = new CreatorFileTaskUnit(computeResult);
            ForkJoinTask<String> stringForkJoinTask = creatorFileTaskUnit.fork();
            fileName = stringForkJoinTask.join();
        }
        return fileName;
    }

    /**
     * 改变状态数组元素的状态[上下中左右]
     *
     * @param centerIndex 数组下标
     */
    private void changeStatus(int centerIndex) {

        //centerIndex
        switchStatus(centerIndex);

        int row = centerIndex / edge;
        int column = centerIndex % edge;

        int top = row - 1;
        int bottom = row + 1;
        int left = column - 1;
        int right = column + 1;

        if (top >= 0) {
            int topIndex = top * edge + column;
            switchStatus(topIndex);
        }
        if (bottom < edge) {
            int bottomIndex = bottom * edge + column;
            switchStatus(bottomIndex);
        }
        if (left >= 0) {
            int leftIndex = centerIndex - 1;
            switchStatus(leftIndex);
        }
        if (right < edge) {
            int rightIndex = centerIndex + 1;
            switchStatus(rightIndex);
        }
    }

    private void switchStatus(int index) {
        status[index] = (status[index] == ZERO ? ONE :
                ZERO);
    }
}